﻿//////////////////////////////////////////////////////////////////////////////
//
//  Copyright © 1998-2024 Glodon Company Limited.  All rights reserved.
//
//  Use of this software is subject to the terms of the Glodon license
//  agreement provided at the time of installation or download, or which
//  otherwise accompanies this software in either electronic or hard copy form.  
//
//////////////////////////////////////////////////////////////////////////////

// Reviewed

#pragma once


#include "Vector3d.h"
#include "Matrix4dUtils.h"
#include "GbmpConstants.h"
#include "GcmpApiDeclaration.h"

namespace gcmp
{

    class Matrix4d;

    /// \brief  三维坐标系定义
    ///
    /// 
    class GCMP_MATH_INTERFACE_EXPORT Coordinate3d
    {
    public:
        DEFINE_VISUAL_TYPE_DOUBLE()

    public:
        /// \brief   由原点和X、Y轴生成坐标系
        ///
        /// \param pos    原点
        /// \param dirX   X轴
        /// \param dirY   Y轴
        /// \return  构建的坐标系
        static Coordinate3d CreateFromAxis(const Vector3d& pos, const Vector3d& dirX, const Vector3d& dirY);

        /// \brief   获取坐标系原点
        ///
        /// \return  坐标系原点
        const Vector3d& GetOrigin() const;

        
        /// \brief   由世界坐标点得到局部坐标点
        ///
        /// \param worldPoint  世界坐标点
        /// \return  局部坐标
        Vector3d GetLocalPoint(const Vector3d& worldPoint) const;

        /// \brief  由世界向量得到局部向量
        ///
        /// \param worldVec  世界向量
        /// \return  局部坐标
        Vector3d GetLocalVector(const Vector3d& worldVec) const;

        /// \brief   由局部坐标得到世界坐标
        ///
        /// \param localPoint  局部坐标点
        /// \return   世界坐标点
        Vector3d GetWorldPoint(const Vector3d& localPoint) const;

        /// \brief    由局部向量得到世界向量
        ///
        /// \param localVec  局部向量
        /// \return   世界向量
        Vector3d GetWorldVector(const Vector3d& localVec) const;

        /// \brief   获得由世界坐标到局部坐标的变换矩阵
        ///
        /// \param matrix  返回的变换矩阵
        /// \return  true: 成功， false: 失败
        bool GetLocalMatrix(Matrix4d& matrix) const;

        /// \brief   获得由局部坐标到世界坐标的变换矩阵
        ///
        /// \param matrix  返回的变换矩阵
        /// \return  true: 成功， false: 失败 
        bool GetWorldMatrix(Matrix4d& matrix) const;

        /// \brief   获得由当前坐标系到目标坐标系的变换矩阵
        /// 
        /// 该接口实现有问题，请使用 GetTransformMatrix(Matrix4d& matrix, const Coordinate3d& target)
        /// \param target  目标坐标系
        /// \param matrix  返回的变换矩阵
        /// \return true: 成功， false: 失败 
        bool GetTransformMatrix(const Coordinate3d& target, Matrix4d& matrix) const;

        /// \brief   获得由当前坐标系到目标坐标系的变换矩阵
        ///        
        /// \param matrix  返回的变换矩阵
        /// \param target  目标坐标系
        /// \return true: 成功， false: 失败 
        bool GetTransformMatrix(Matrix4d& matrix, const Coordinate3d& target) const;

        /// \brief   由原点，X轴，Y轴构建坐标系
        ///
        /// \param pos   原点
        /// \param dirX  X轴
        /// \param dirY  Y轴
        /// \return   true: 成功， false: 失败 
        bool Set(const Vector3d& pos, const Vector3d& dirX, const Vector3d& dirY);

        /// \brief   当前坐标系进行矩阵变换
        ///
        /// \param matrix 变换矩阵
        /// \return  true: 成功， false: 失败 
        bool Transform(const Matrix4d& matrix);

        const Vector3d& GetX() const;
        const Vector3d& GetY() const;
        const Vector3d& GetZ() const;


    public :

        /// \brief  默认的构造函数
        /// 
        Coordinate3d();

        /// \brief   构造函数，由原点，X轴，Y轴生成右手正交坐标系
        ///
        /// \param pos   原点
        /// \param unitDirX  X轴
        /// \param unitDirY  Y轴
        ///
        Coordinate3d(const Vector3d& pos, const Vector3d& unitDirX, const Vector3d& unitDirY);

        /// \brief  构造函数，由原点和法向生成右手正交坐标系
        ///
        /// \param pos   原点
        /// \param normal 法向
        ///
        Coordinate3d(const Vector3d& pos, const Vector3d& normal);

        /// \brief  拷贝构造函数
        ///
        /// \param src 输入坐标系
        /// 
        Coordinate3d(const Coordinate3d& src);

        /// \brief  获取X轴
        ///
        /// \return X轴
        const Vector3d& X() const;

        /// \brief  获取Y轴
        ///
        /// \return Y轴
        const Vector3d& Y() const;

        /// \brief  获取Z轴
        ///
        /// \return Z轴
        const Vector3d& Z() const;

        /// \brief  获取原点
        ///
        /// \return 原点
        const Vector3d& Origin() const;

        /// \brief   由原点和法向构建坐标系
        ///
        /// \param pos  原点
        /// \param normal  法向
        /// \return  true: 成功， false, 失败
        bool Set(const Vector3d& pos, const Vector3d& normal);
 
        /// \brief   计算将三维点从全局坐标系转换到当前坐标系下在XoY平面上二维点
        ///
        /// \param worldPoint  三维点
        /// \return   转换以后的二维点
        Vector2d GetLocalPointXY(const Vector3d& worldPoint)const;

        /// \brief   计算将向量从全局坐标系转换到当前坐标系下在XoY平面上的二维向量
        ///
        /// \param worldVec  向量
        /// \return  转换以后的二维向量
        Vector2d GetLocalVectorXY(const Vector3d& worldVec)const;

        /// \brief 把坐标系对象按照规定格式字符串输出
        ///
        /// \return 字符串
        std::wstring GetStringForDebug() const;


        /// \brief    【请勿使用】构造函数，由原点，X轴，Y轴，Z轴生成右手仿射坐标系,仅支持右手坐标系，目前无法删去，因为GmModelViewUtil::GetModelViewBox内部存在左手坐标系
        ///
        /// \param pos   原点
        /// \param unitDirX  X轴，单位向量
        /// \param unitDirY  Y轴，单位向量
        /// \param unitDirZ  Z轴，单位向量
        /// 
        Coordinate3d(const Vector3d& pos, const Vector3d& unitDirX, const Vector3d& unitDirY, const Vector3d& unitDirZ);

    private:
            /// \brief   根据向量z，生成坐标轴
            ///
            /// \param z  坐标轴Z
            /// 
        void ZAxisCoordinates(const Vector3d& z);

    private:

        ///坐标系的原点
        Vector3d m_origin;

        ///坐标系的X轴
        Vector3d m_x;

        ///坐标系的Y轴
        Vector3d m_y;

        ///坐标系的Z轴
        Vector3d m_z;

    };

    GCMP_MATH_INTERFACE_EXPORT bool operator<(const Coordinate3d& coord1, const Coordinate3d& coord2);

} // namespace




